home *** CD-ROM | disk | FTP | other *** search
- ;;;; compiler.scm: Program for compiling SCMINT code to C
- ;;; Copyright (C) 1991, 1992, 1993 Aubrey Jaffer.
-
- (define __STDC__ #f)
- ;;; (define __STDC__ #t) if you want ANSI function prototypes.
-
- ;;; REPORT an error or warning
- (define report
- (lambda args
- (display "WARNING: char ")
- (display (file-position *compile-input*))
- (display "-> line ")
- (display *output-line*)
- (display #\ )
- (display (list *procedure*))
- (display ": ")
- (apply qreport args)))
-
- (define qreport
- (lambda args
- (for-each (lambda (x) (write x) (display #\ )) args)
- (newline)))
-
- ;;;delete the next four lines if you are not using SLIB.
- (require 'rev3-procedures) ;this brings in last-pair
- (require 'debug)
- (set! *qp-width* 100)
- (define qreport qp)
-
- ;;; This allows us to test without generating files
- (define *compile-input* (current-input-port))
- (define *compile-output* (current-output-port))
- (define *prototype-output* (current-output-port))
-
- (define *included-files* '())
- (define *label-list* '())
- (define *procedure* #f)
- (define *output-line* 0)
- (define tokcntr 0)
- (define VOID 'VOID)
- (define EXTERN 'EXTERN)
- (define VAL 'VAL)
- (define LONG 'LONG)
- (define BOOL 'BOOL)
- (define CONTLINE -80)
-
- (define RETURN "return")
- (define NONE "")
- (define COMMA ",")
- (define SEMI ";")
-
- ;;; OUT indents and displays the arguments
- (define (out indent . args)
- (cond ((>= indent 0)
- (newline *compile-output*)
- (set! *output-line* (+ 1 *output-line*))
- (do ((j indent (- j 8)))
- ((> 8 j)
- (do ((i j (- i 1)))
- ((>= 0 i))
- (display #\ *compile-output*)))
- (display #\ *compile-output*))))
- (for-each (lambda (a)
- (cond ((symbol? a)
- (c-ify-symbol a *compile-output*))
- (else
- (display a *compile-output*))))
- args))
-
- ;;; C-IFY-SYMBOL removes or translates characters from name and prints to port
- (define (c-ify-symbol name port)
- (define visible? #f)
- (for-each
- (lambda (c)
- (let ((tc (cond ((char-alphabetic? c) c)
- ((char-numeric? c) c)
- ((char=? c #\-) #\_)
- ((char=? c #\_) #\_)
- ((char=? c #\?) "_P")
- (else #f))))
- (if tc (begin (set! visible? #t) (display tc port)))))
- (string->list (symbol->string name)))
- (if (not visible?) (report "C-invisible symbol?" name)))
-
- ;;; TMPIFY makes a name for a temporary variable
- (define (tmpify sym)
- (string->symbol (string-append "T_" (symbol->string sym))))
-
- ;;; LBLIFY makes a name for a label
- (define (lblify sym)
- (string->symbol (string-append "L_" (symbol->string sym))))
-
- (define LONG 'LONG)
- (define INT 'INT)
- (define PTR 'PTR)
- (define ARRAY 'ARRAY)
- (define PAIR 'PAIR)
-
- ;;; TYPTRANS is a translation table from variable name to C type.
- (define typtrans
- '(("pos" INT) ("tab" PTR) ("ara" ARRAY) ("end" INT) ("siz" INT) ("eld" INT)
- ("ort" SHORT) ("ent" (PTR ENTRY)) ("nts" (PTR ENTRY))
- ("buk" (PTR ENTRY)) ("ile" PORT) ("ype" INT)
- ("num" LONG) ("blk" (ARRAY UCHAR)) ("-id" LONG)
- ("fct" LONG) ("-ct" LONG)
- ("lck" (PTR LCK)) ("ntr" INT) ("unt" INT)
- ("flc" (PTR LONG)) ("vel" INT) ("len" INT)
- ("pkt" (ARRAY INT)) ("ame" (PTR UCHAR))
- ("ind" (PTR ENTRY)) ("-bt" (PTR HAND))
- ("str" (ARRAY UCHAR)) ("sed" LONG) ("han" (PTR HAND))
- ("egd" (PTR SEGD)) ("ong" LONG) ("ime" LONG)
- ("fun" (FUNCTION INT)) ("unc" (FUNCTION INT))))
-
- ;;; VARTYPE gives a guess for the type of var
- (define (vartype var)
- (let* ((str (symbol->string var))
- (len (string-length str)))
- (let ((v (if (>= len 3)
- (assoc (substring str (- len 3) len) typtrans)
- #f)))
- (if (and v (memq (cadr v) '(ARRAY PTR)) (>= len 4))
- (list (cadr v)
- (vartype (string->symbol (substring str 0 (- len 4)))))
- (or (and v (cadr v)) INT)))))
-
- ;;; PROCTYPE - gives a guess for the type of proc
- (define (proctype proc)
- (let* ((str (symbol->string proc)))
- (case (string-ref str (- (string-length str) 1))
- ((#\?) BOOL)
- ((#\!) VOID)
- (else (or (vartype proc)
- (begin (report "unknown type" proc)
- VAL))))))
-
- (define (type->exptype type)
- (case type
- ((VOID BOOL LONG) type)
- (else VAL)))
-
- (define (outtype indent type name val)
- (cond ((symbol? type)
- (out indent
- (case type
- ((INT) "int")
- ((BOOL) "int")
- ((LONG) "unsigned long")
- ((SHORT) "short")
- ;;; ((CHAR) "char")
- ((UCHAR) "unsigned char")
- ((LCK) "LCK")
- ((SEGD) "SEGD")
- ((HAND) "HAND")
- ((ENTRY) "ENTRY")
- ((PORT) "int")
- ((VAL) "SCM")
- (else type))
- #\ name) #t)
- ((pair? type)
- (case (car type)
- ((PTR)
- (outtype indent (cadr type) NONE VOID)
- (out CONTLINE "*" name) #t)
- ((ARRAY)
- (outtype indent (cadr type) NONE VOID)
- (cond ((and (pair? val)
- (memq (car val) '(MAKE-VECTOR MAKE-STRING))
- (pair? (cdr val))
- (null? (cddr val)))
- (out CONTLINE name "[")
- (compile-exp "]" INT indent (cadr val)) #f)
- ((and (pair? val)
- (memq (car val) '(VECTOR STRING)))
- (out CONTLINE name "[]") #t)
- ((string? val)
- (out CONTLINE name "[]") #t)
- ((vector? val)
- (out CONTLINE name "[]") #t)
- ((eq? val EXTERN)
- (out CONTLINE name "[]") #t)
- (else
- (out CONTLINE "*" name) #t)))
- ((FUNCTION)
- (out indent (string-append (symbol->string (cadr type)) "_function ") name) #f)
- ; ((FUNCTION)
- ; (outtype indent (cadr type) NONE VOID)
- ; (out CONTLINE "(*" name ")()") #f)
- (else (report "unknown type" type name) #f)))
- (else (report "unknown type" type name) #f)))
-
- ;;; OUTBINDING - indents and prints out local binding
- (define (outbinding indent b)
- (let ((type (vartype (car b))))
- (cond ((var-involved? (car b) (cadr b))
- (report "rebinding variable" b)
- (outtmpbnd indent (car b) (cadr b))
- (outuntmpbnd indent (car b)))
- ((outtype indent type (car b) (cadr b))
- (out CONTLINE " = ")
- (compile-exp SEMI (type->exptype type) indent (cadr b)))
- (else
- ; (report "var can't be assigned" b)
- (out CONTLINE ";")))))
-
- ;;; OUTBINDINGS - indents and prints out local bindings
- (define (outbindings indent b)
- (for-each (lambda (b) (outbinding indent b)) b))
-
- (define (outtmpbnd indent var val)
- (let ((type (vartype var)))
- (cond ((outtype indent type (tmpify var) val)
- (out CONTLINE " = ")
- (compile-exp SEMI (type->exptype type) indent val))
- (else
- (report "temp can't be assigned" var val)
- (out CONTLINE ";")))))
-
- (define (outuntmpbnd indent var)
- (outtype indent (vartype var) var VOID)
- (out CONTLINE " = " (tmpify var) SEMI))
-
- ;;; OUTLETBINDINGS - indents and prints out local simultaneous bindings
- (define (outletbindings indent bindings types?)
- (if (not (null? bindings))
- (let* ((vars (map car bindings))
- (exps (map cadr bindings))
- (invol (map
- (lambda (b)
- (var-involved-except? (car b) bindings b))
- bindings)))
- (for-each
- (lambda (v b i) (if i (outtmpbnd indent (car b) (cadr b))))
- vars bindings invol)
- ; (if types? (outbinding indent (car bindings))
- ; (let ((vtype (vartype (caar bindings))))
- ; (out indent (caar bindings) " = ")
- ; (compile-exp SEMI (type->exptype vtype) indent (cadar bindings))))
- (for-each
- (lambda (v b i)
- (let ((type (vartype (car b))))
- (cond (i (if types? (outuntmpbnd indent v)
- (out indent v " = " (tmpify v) SEMI)))
- ((not types?)
- (out indent (car b))
- (out CONTLINE " = ")
- (compile-exp SEMI (type->exptype type) indent (cadr b)))
- ((outtype indent type (car b) (cadr b))
- (out CONTLINE " = ")
- (compile-exp SEMI (type->exptype type) indent (cadr b)))
- (else ;(report "can't initialize" b)
- (out CONTLINE SEMI)))))
- (reverse vars) (reverse bindings) (reverse invol)))))
-
- (define (var-involved-except? var sexps own)
- (if (null? sexps) #f
- (if (eq? (car sexps) own)
- (var-involved-except? var (cdr sexps) own)
- (or (var-involved? var (cdar sexps))
- (var-involved-except? var (cdr sexps) own)))))
-
- (define (var-involved? var sexp )
- (if (pair? sexp)
- (or (var-involved? var (car sexp))
- (var-involved? var (cdr sexp)))
- (eq? sexp var)))
-
- (define (outcomment indent str)
- (out indent "/*" str "*/")
- (out indent))
-
- (define (descmfilify file)
- (let ((sl (string-length file)))
- (cond ((< sl 4) file)
- ((string-ci=? (substring file (- sl 4) sl) ".scm")
- (substring file 0 (- sl 4)))
- (else file))))
-
- (define (out-include spec)
- (cond ((and (pair? spec) (eq? (car spec) 'quote) (symbol? (cadr spec))))
- (else
- (out 0 "#include ")
- (cond ((not (pair? spec))
- (out CONTLINE "\"" (descmfilify spec) ".h\""))
- ((and (eq? 'IN-VICINITY (car spec))
- (eq? 'LIBRARY-VICINITY (caadr spec)))
- (out CONTLINE "<" (descmfilify (caddr spec)) ".h>"))
- (else
- (out CONTLINE "\"" (descmfilify (caddr spec)) ".h\"")
- (if (not (member (caddr spec) *included-files*))
- (set! *included-files*
- (cons (caddr spec) *included-files*))))))))
-
- (define (do-includes)
- (cond ((not (null? *included-files*))
- (display "include files are:") (newline)
- (for-each (lambda (f) (write f) (newline)) *included-files*)
- (set! *included-files* ())))
- (newline) (display "done.") (newline))
-
- ;;; COMPILE files.
- (define compile
- (lambda files
- (for-each (lambda (f) (compile1 f ".c")) files)
- (do-includes)))
-
- ;;; COMPILEH - compile file to file.h. Include files are done this way.
- (define compileh
- (lambda files
- (for-each (lambda (f) (compile1 f ".h")) files)
- (do-includes)))
-
- ;;; COMPILE1 - compile file.scm to file.suffix
- (define (compile1 file suffix)
- (define ofile (string-append (descmfilify file) suffix))
- (display "compiling ")
- (write file)
- (display " -> ")
- (write ofile)
- (newline)
- (set! *compile-input* (open-input-file file))
- (set! *compile-output* (open-output-file ofile))
- (cond ((equal? ".c" suffix)
- (if __STDC__ (display "ANSI "))
- (display "prototypes -> ")
- (write (string-append (descmfilify file) ".h"))
- (newline)
- (set! *prototype-output*
- (open-output-file (string-append (descmfilify file) ".h")))))
- (set! *output-line* 0)
- (set! tokcntr 0)
- (if (equal? ".c" suffix)
- (compile-tops)
- (compileh-tops))
- (close-input-port *compile-input*)
- (close-output-port *compile-output*)
- (if (equal? ".c" suffix)
- (begin (close-output-port *prototype-output*)
- (set! *prototype-output* (current-output-port))))
- (set! *compile-input* (current-input-port))
- (set! *compile-output* (current-output-port)))
-
- ;;; COMPILEH-TOPS - compile top level forms.
- (define (compileh-tops)
- (let ((sexp (read *compile-input*)))
- (cond ((eof-object? sexp))
- (else
- (compileh-top sexp)
- (compileh-tops)))))
-
- ;;; COMPILEH-TOP - compile top level form sexp.
- (define (compileh-top sexp)
- (cond ((symbol? sexp) (set! *procedure* sexp))
- ((and (pair? sexp) (eq? (car sexp) 'QUOTE))
- (set! *procedure* (cadr sexp)))
- ((string? sexp) (outcomment 0 sexp))
- ((not (pair? sexp))
- (report "top level atom?" sexp))
- (else
- (case (car sexp)
- ((load require) ;If you redefine load, you lose
- (out-include (cadr sexp)))
- ((begin)
- (for-each compileh-top (cdr sexp)))
- ((define)
- (if (pair? (cadr sexp))
- (let* ((ptype (or *procedure* (proctype (caadr sexp))))
- (use (type->exptype ptype)))
- (set! *procedure* (caadr sexp))
- (out 0 "#define " (caadr sexp)) ;name
- (infix-compile-exp VAL #\, CONTLINE (cdadr sexp)) ;arglist
- (out CONTLINE " ")
- (compile-bracketed-begin (if (eq? VOID use) SEMI NONE)
- use CONTLINE (cddr sexp)))
- (begin (out 0 "#define " (cadr sexp) #\ )
- (compile-exp NONE VAL CONTLINE
- (if (and (pair? (caddr sexp))
- (eq? 'QUOTE (caaddr sexp))
- (eq? (cadr sexp) (cadr (caddr sexp))))
- (begin (set! tokcntr (+ 1 tokcntr)) tokcntr)
- (caddr sexp)))))
- (out 0))
- (else
- (report "statement not in procedure" sexp)))
- (set! *procedure* #f))))
-
- ;;; COMPILE-TOPS - compile top level forms.
- (define (compile-tops)
- (let ((sexp (read *compile-input*)))
- (cond ((eof-object? sexp))
- (else
- (compile-top sexp)
- (compile-tops)))))
-
- ;;; COMPILE-TOP - compile top level form sexp.
- (define (compile-top sexp)
- (cond ((symbol? sexp) (set! *procedure* sexp))
- ((and (pair? sexp) (eq? (car sexp) 'QUOTE))
- (set! *procedure* (cadr sexp)))
- ((string? sexp) (outcomment 0 sexp))
- ((not (pair? sexp))
- (report "top level atom?" sexp))
- (else
- (case (car sexp)
- ((load require) ;If you redefine load, you lose
- (out-include (cadr sexp)))
- ((begin)
- (for-each compile-top (cdr sexp)))
- ((define)
- (if (pair? (cadr sexp))
- (let ((ptype (or *procedure* (proctype (caadr sexp)))))
- (set! *procedure* (caadr sexp))
- (let ((compile-output *compile-output*)
- (output-line *output-line*))
- (set! *compile-output* *prototype-output*)
- (outtype 0 ptype (caadr sexp) VOID) ;name
- (out CONTLINE "(")
- (if __STDC__
- (if (null? (cdadr sexp)) (out CONTLINE "void")
- (let ((bs (cdadr sexp)))
- (outtype CONTLINE (vartype (car bs)) (car bs) VOID)
- (for-each (lambda (b)
- (out CONTLINE COMMA)
- (outtype CONTLINE (vartype b) b VOID))
- (cdr bs)))))
- (out CONTLINE ");")
- (out 0)
- (set! *compile-output* compile-output)
- (set! *output-line* output-line))
- (add-label (caadr sexp) (cdadr sexp))
- (outtype 0 ptype (caadr sexp) VOID) ;name
- (infix-compile-exp VAL #\, CONTLINE (cdadr sexp)) ;arglist
- (for-each (lambda (b)
- (outtype 5 (vartype b) b VOID)
- (out CONTLINE SEMI))
- (cdadr sexp))
- (out 0 #\{)
- (out 0 (lblify (caadr sexp)) #\:)
- (cond ((has-defines? (cddr sexp))
- (out 2)
- (compile-bracketed-begin
- RETURN (type->exptype ptype) 2 (cddr sexp)))
- (else
- (compile-body RETURN (type->exptype ptype) 2 (cddr sexp))))
- (out 0 #\})
- (rem-label (caadr sexp)))
- (begin
- (let ((compile-output *compile-output*)
- (output-line *output-line*))
- (set! *compile-output* *prototype-output*)
- (out 0 "extern ")
- (outtype CONTLINE (vartype (cadr sexp)) (cadr sexp)
- (and (caddr sexp) 'EXTERN)) ;name
- (out CONTLINE SEMI)
- (out 0)
- (set! *compile-output* compile-output)
- (set! *output-line* output-line))
- (outbinding 0 (cdr sexp))))
- (out 0))
- (else
- (report "statement not in procedure" sexp)))
- (set! *procedure* #f))))
-
- (define (has-defines? body)
- (cond ((null? body) #f)
- ((null? (cdr body)) #f)
- ((not (pair? (car body))) (has-defines? (cdr body)))
- ((eq? 'BEGIN (caar body)) (has-defines? (cdar body)))
- (else (eq? 'DEFINE (caar body)))))
-
- ;;; COMPILE-BODY - compile body
- (define (compile-body termin use indent body)
- (if (and (not (eq? RETURN termin)) (not (eq? use VOID)))
- (report "body value not at top level" body))
- (cond ((not (pair? body))
- (if (not (eq? use VOID))
- (report "short body?" body)))
- ((null? (cdr body))
- (out indent)
- (compile-exp termin use indent (car body)))
- ((string? (car body))
- (outcomment indent (car body))
- (compile-body termin use indent (cdr body)))
- ((not (eq? (caar body) 'DEFINE))
- (out indent)
- (compile-exp SEMI VOID indent (car body))
- (compile-body termin use indent (cdr body)))
- ((symbol? (cadar body))
- (outbinding indent (cdar body))
- (compile-body termin use indent (cdr body)))
- (else (add-label (caadar body) (cdadar body))
- (for-each (lambda (b)
- (outtype indent (vartype b) b VOID)
- (out CONTLINE SEMI))
- (cdadar body))
- (compile-body termin use indent (cdr body))
- (if (and (eq? use VOID) (eq? termin RETURN))
- (out indent "return;"))
- (out 0 (lblify (caadar body)) #\:)
- (compile-body termin use indent (cddar body))
- (rem-label (caadar body)))))
-
- (define (compile-goto indent sexp)
- (let ((lv (filter (lambda (l)
- (not (eq? (car l) (cadr l))))
- (map list (label-vars (car sexp)) (cdr sexp)))))
- (cond ((pair? lv)
- (out CONTLINE "{")
- (outletbindings (+ 1 indent) lv #f)
- (out (+ 1 indent) "goto " (lblify (car sexp)) #\;)
- (out indent "}"))
- (else
- (out CONTLINE "goto " (lblify (car sexp)) #\;)))))
-
- (define (filter pred? lst)
- (cond ((null? lst) lst)
- ((pred? (car lst))
- (cons (car lst) (filter pred? (cdr lst))))
- (else (filter pred? (cdr lst)))))
-
- ;;; LOOKUP - translate from table or return arg as string
- (define (lookup arg tab)
- (let* ((p (assq arg tab))
- (l (if p (cdr p) arg)))
- (if (symbol? l) (symbol->string l) l)))
-
- ;;; COMPILE-EXP - compile expression
- (define (compile-exp termin use indent sexp)
- (cond ((not (pair? sexp)) ;atoms
- (cond ((eq? RETURN termin) ;return from here
- (case use
- ((VAL BOOL LONG)
- (out CONTLINE "return ")
- (compile-exp SEMI use (+ indent 7) sexp))
- ((VOID) ;shouldn't happen
- (if sexp
- (begin (report "void function returning?" sexp)
- (compile-exp SEMI use indent sexp)))
- (out indent "return;"))))
- ((string? sexp)
- (out CONTLINE #\" sexp #\" termin))
- ((integer? sexp)
- (out CONTLINE sexp (if (eq? use LONG) #\L "") termin))
- ((char? sexp)
- (out CONTLINE "'"
- (case sexp
- ((#\newline) "\\n")
- ((#\tab) "\\t")
- ((#\backspace) "\\b")
- ((#\return) "\\r")
- ((#\page) "\\f")
- ((#\null) "\\0")
- (else sexp))
- "'"
- termin))
- ((vector? sexp)
- (out CONTLINE #\{)
- (infix-compile-exp VAL #\, indent (vector->list sexp))
- (out CONTLINE "}" termin))
- ((eq? VOID use)
- (if sexp (report "returning value?" sexp))
- (out CONTLINE termin))
- (else (out CONTLINE (case sexp ((#f) 0) ((#t) "!0") (else sexp)) termin))))
- ((and (pair? (car sexp))
- (eq? 'LAMBDA (caar sexp)))
- (compile-exp termin use indent
- (append (list 'LET (map list (cadar sexp) (cdr sexp)))
- (cddar sexp))))
- ((case (car sexp)
- ((IF)
- (compile-if termin use indent (cdr sexp)) #t)
- ((OR)
- (compile-or termin use indent (cdr sexp)) #t)
- ((AND)
- (compile-and termin use indent (cdr sexp)) #t)
- ((COND)
- (compile-cond termin use indent (cdr sexp)) #t)
- ((BEGIN)
- (compile-begin termin use indent (cdr sexp)) #t)
- ((DO)
- (compile-do termin use indent (cdr sexp)) #t)
- ((LET)
- (compile-let termin use indent (cdr sexp)) #t)
- ((LET*)
- (compile-let* termin use indent (cdr sexp)) #t)
- ((CASE)
- (compile-case termin use indent (cdr sexp)) #t)
- (else
- (and (label? (car sexp))
- (cond ((not (eq? termin RETURN))
- (if (eq? (car sexp) *procedure*) #f
- (report "internal recursion not tail recursion" sexp))
- #f)
- (else
- (compile-goto indent sexp)
- #t))))))
- (else
- (if (and (eq? RETURN termin) (not (eq? use VOID)))
- (begin (out CONTLINE "return ")
- (set! indent (+ indent 7))))
- (case (car sexp)
- ((SET!)
- (if (not (eq? use void)) (report "returning to void?" sexp))
- (out CONTLINE (cadr sexp) " = ")
- (compile-exp NONE (type->exptype (vartype (cadr sexp))) indent (caddr sexp)))
- ((VECTOR-SET! STRING-SET!)
- (if (not (eq? use void)) (report "returning to void?" sexp))
- (compile-exp NONE VAL indent (cadr sexp))
- (out CONTLINE #\[)
- (compile-exp NONE VAL indent (caddr sexp))
- (out CONTLINE #\] " = ") ;TBD could be smarter about type of expression in vector-set!
- (compile-exp NONE VAL indent (cadddr sexp)))
- ((VECTOR-REF STRING-REF)
- (compile-exp NONE VAL CONTLINE (cadr sexp))
- (out CONTLINE #\[)
- (compile-exp NONE VAL CONTLINE (caddr sexp))
- (out CONTLINE #\]))
- ((VECTOR STRING)
- (out CONTLINE #\{)
- (infix-compile-exp use "," (+ 2 indent) (cdr sexp))
- (out CONTLINE #\}))
- ((VECTOR-SET-LENGTH!)
- (out CONTLINE "realloc(")
- (compile-exp NONE use (+ 2 indent) (cadr sexp))
- (out CONTLINE ", (")
- (compile-exp NONE use (+ 2 indent) (caddr sexp))
- (out CONTLINE ") * (sizeof (void *)))"))
- ((MAKE-VECTOR)
- (case (length sexp)
- ((2) (out CONTLINE "malloc((")
- (compile-exp NONE use (+ 2 indent) (cadr sexp))
- (out CONTLINE ") * (sizeof (void *)))"))
- ((3) (if (not (member (caddr sexp) '(#f () 0)))
- (report "cannot initialize to other than 0 " sexp))
- (out CONTLINE "calloc(")
- (compile-exp NONE use (+ 2 indent) (cadr sexp))
- (out CONTLINE ", (sizeof (void *)))"))))
- ((STRING-LENGTH VECTOR-LENGTH)
- (out CONTLINE "sizeof(")
- (compile-exp NONE use (+ 2 indent) (cadr sexp))
- (out CONTLINE (if (eq? 'STRING-LENGTH (car sexp)) ")-1" ")")))
- ((NUMBER? CHAR?)
- (out CONTLINE "(1)"))
- ((ZERO? NEGATIVE? POSITIVE? NOT INTEGER->CHAR CHAR->INTEGER MAKE-STRING LOGNOT)
- (out CONTLINE
- (lookup (car sexp)
- '((NOT . "!") (ZERO? . "!") (NEGATIVE? . "0 > ")
- (POSITIVE? . "0 < ") (INTEGER->CHAR . "")
- (CHAR->INTEGER . "(unsigned)")
- (MAKE-STRING . "(unsigned char *)malloc")
- (LOGNOT . "~")))
- "(")
- (compile-exp NONE use (+ 2 indent)(cadr sexp))
- (out CONTLINE ")"))
- ((- + * REMAINDER QUOTIENT LOGIOR LOGAND LOGXOR)
- (infix-compile-exp use
- (lookup (car sexp)
- '((REMAINDER . %) (QUOTIENT . /)
- (LOGIOR . |) (LOGAND . &)
- (LOGXOR . ^)))
- indent
- (cdr sexp)))
- ((< > = <= >= EQ? EQV? CHAR<? CHAR>? CHAR<=? CHAR>=? CHAR=?)
- (infix-compile-exp VAL
- (lookup (car sexp)
- '((= . ==) (EQ? . ==) (EQV? . ==)
- (CHAR<? . <) (CHAR>? . >)
- (CHAR<=? . <=) (CHAR>=? . >=) (CHAR=? . ==)))
- indent
- (cdr sexp)))
- (else
- (cond ((pair? (car sexp)) ;computed function
- (out indent "(*(")
- (compile-exp NONE VAL (+ 3 indent) (car sexp))
- (out CONTLINE "))")
- (out (+ 2 indent)))
- (else (out CONTLINE (car sexp))))
- (infix-compile-exp VAL #\, (+ 2 indent) (cdr sexp))))
- (cond ((eq? VOID use)
- ; (if (not (eq? VOID (proctype (car sexp))))
- ; (report "void function returning?" sexp))
- (out CONTLINE (if (eq? COMMA termin) COMMA SEMI))
- ; (if (eq? RETURN termin) (out indent "return;"))
- )
- ((eq? RETURN termin)
- (out CONTLINE #\;))
- (else (out CONTLINE termin))))))
-
- (define (compile-begin termin use indent exps)
- (cond ((null? exps) (outcomment CONTLINE "null begin?"))
- ((null? (cdr exps))
- (compile-exp termin use indent (car exps)))
- (else (compile-bracketed-begin termin use indent exps))))
-
- (define (compile-bracketed-begin termin use indent exps)
- (cond ((and (not (eq? RETURN termin)) (not (eq? VOID use)))
- (out CONTLINE #\()
- (compile-exps use (+ 1 indent) exps)
- (out CONTLINE #\) termin))
- ((and (pair? exps)
- (null? (cdr exps))
- (pair? (car exps))
- (or (not (eq? use VOID))
- (memq (caar exps) '(BEGIN DO LET LET*))))
- (compile-exp termin use indent (car exps)))
- (else
- (out CONTLINE #\{)
- (compile-body termin use (+ 1 indent) exps)
- (out indent "}"))))
-
- ;;; COMPILE-EXPS - compile expressions separated by commas
- (define (compile-exps use indent exps)
- (cond ((null? (cdr exps))
- (compile-exp NONE use indent (car exps)))
- (else
- (compile-exp COMMA VOID indent (car exps))
- ;VOID causes if statements inside parenthesis.
- (compile-exps use indent (cdr exps)))))
-
- (define (clause->sequence clause)
- (cond ((not (pair? clause)) (report "bad clause" clause) clause)
- ((null? (cdr clause)) (car clause))
- (else (cons 'BEGIN clause))))
-
- (define (compile-cond termin use indent clauses)
- (if (not (null? clauses))
- (let* ((clause (car clauses)))
- (cond ((null? (cdr clause))
- (compile-or termin use indent (list (car clause)
- (cons 'COND (cdr clauses)))))
- ((eq? 'ELSE (car clause))
- (compile-begin termin use indent (cdr clause)))
- ((not (null? (cdr clauses)))
- (compile-if termin use indent
- (list (car clause)
- (clause->sequence (cdr clause))
- (cons 'COND (cdr clauses)))))
- (else
- (compile-if termin use indent
- (list (car clause)
- (clause->sequence (cdr clause)))))))))
-
- (define (compile-if termin use indent exps)
- (if (and (not (eq? RETURN termin)) (not (eq? use VOID)))
- (begin
- (compile-exp NONE BOOL (+ 4 indent) (car exps))
- (out (+ 1 indent) #\?)
- (compile-exp NONE use (+ 2 indent) (cadr exps))
- (out (+ 1 indent) #\:)
- (if (null? (cddr exps))
- (report "value from if missing" exps)
- (compile-exp termin use (+ 2 indent) (caddr exps))))
- (begin
- (out CONTLINE "if (")
- (compile-exp NONE BOOL (+ 4 indent) (car exps))
- (out CONTLINE ")")
- (out (+ 2 indent))
- (if (null? (cddr exps))
- (compile-begin termin use (+ 2 indent) (cdr exps)) ;no else
- (begin ;have an else clause
- (if (and (eq? use VOID) (cadr exps))
- (compile-bracketed-begin termin use (+ 2 indent) (list (cadr exps)))
- (compile-begin termin use (+ 2 indent) (list (cadr exps))))
- (out indent "else ")
- (compile-begin termin use indent (cddr exps)))))))
-
- (define (compile-or termin use indent exps)
- (if (eq? termin RETURN)
- (case (length exps)
- ((0) (if (eq? VOID use)
- (out CONTLINE "return;")
- (out CONTLINE "return 0;")))
- ((1) (compile-exp termin use indent (car exps)))
- (else
- (case use
- ((BOOL) (out CONTLINE "return ")
- (compile-or SEMI use (+ 7 indent) exps))
- ((VOID) (compile-or SEMI use indent exps)
- (out indent "return;"))
- (else
- (cond ((symbol? (car exps))
- (compile-if termin use indent
- (list (car exps) (car exps) (cons 'OR (cdr exps)))))
- (else
- (let ((procedure-tmp-symbol (tmpify *procedure*)))
- (compile-let* termin use indent
- `(((,procedure-tmp-symbol ,(car exps)))
- (or ,procedure-tmp-symbol ,@(cdr exps)))))))))))
- (case (length exps)
- ((0) (out CONTLINE 0))
- ((1) (compile-exp termin use indent (car exps)))
- (else
- (case use
- ((VAL LONG) (report "or of values not handled properly"))
- ((BOOL) (infix-compile-exp BOOL " || " indent exps))
- ((VOID) (compile-if termin use indent
- (list (car exps) #f (cons 'OR (cdr exps))))))))))
-
- (define (compile-and termin use indent exps)
- (case (length exps)
- ((0) (out CONTLINE (if termin "" "return ") "!0"))
- ((1) (compile-exp termin use indent (car exps)))
- (else
- (case use
- ((BOOL) (infix-compile-exp use " && " indent exps))
- ((VAL)
- (compile-if termin use indent (list (car exps)
- (cons 'AND (cdr exps))
- #f)))
- ((VOID)
- (cond (termin
- (compile-if termin use indent
- (list (cons 'AND (but-last-pair exps))
- (car (last-pair exps)))))
- (else (compile-and SEMI use indent exps)
- (out indent "return;"))))))))
-
- (define (but-last-pair lst)
- (cond ((null? (cdr lst)) '())
- (else
- (cons (car lst) (but-last-pair (cdr lst))))))
-
- (define (compile-let termin use indent exps)
- (cond ((symbol? (car exps))
- (add-label (car exps) (map car (cadr exps)))
- (out CONTLINE #\{)
- (outletbindings (+ indent 1) (cadr exps) #t)
- (out 0 (lblify (car exps)) #\:)
- (compile-body termin use (+ indent 1) (cddr exps))
- (out indent "}")
- (rem-label (car exps)))
- (else
- (out CONTLINE #\{)
- (outletbindings (+ indent 1) (car exps) #t)
- (compile-body termin use (+ indent 1) (cdr exps))
- (out indent "}"))))
-
- (define (compile-let* termin use indent exps)
- (out CONTLINE #\{)
- (outbindings (+ 1 indent) (car exps))
- (compile-body termin use (+ 1 indent) (cdr exps))
- (out indent "}"))
-
- (define (compile-do termin use indent exps)
- (if (and (not (eq? RETURN termin)) (not (eq? use VOID)))
- (report "DO value not at top level" exps))
- (out CONTLINE #\{)
- (outletbindings (+ 2 indent)
- (map (lambda (b) (list (car b) (cadr b))) (car exps))
- #t)
- (out (+ 2 indent) "while (")
- (compile-exp NONE BOOL (+ 7 indent) (list 'NOT (caadr exps)))
- (out CONTLINE ") {")
- (compile-body SEMI VOID (+ 4 indent) (cddr exps))
- (outletbindings
- (+ 4 indent)
- (filter (lambda (l) l)
- (map (lambda (b) (and (= 3 (length b)) (list (car b) (caddr b))))
- (car exps)))
- #f)
- (out (+ 2 indent) "}")
- (compile-body termin use (+ 2 indent) (cdadr exps))
- (out indent "}"))
-
- (define (compile-case termin use indent exps)
- (if (and (not (eq? RETURN termin)) (not (eq? use VOID)))
- (report "CASE value not at top level" exps))
- (out indent "switch (")
- (compile-exp NONE VAL (+ 8 indent) (car exps))
- (out CONTLINE ") {")
- (for-each
- (lambda (x)
- (cond ((eq? (car x) 'ELSE)
- (out indent "default:"))
- (else (for-each (lambda (x)
- (out indent "case " x ":"))
- (car x))))
- (compile-body termin use (+ 3 indent) (cdr x))
- (if (not (eq? RETURN termin))
- (out (+ 3 indent) "break;")))
- (cdr exps))
- (out indent "}"))
-
- (define (add-label name arglist)
- (set! *label-list* (cons (cons name arglist) *label-list*)))
-
- (define (label-vars name)
- (let ((p (label? name)))
- (and p (cdr p))))
-
- (define (rem-label name)
- (set! *label-list* (cdr *label-list*)))
-
- (define (label? name) (assq name *label-list*))
-
- (define (infix-compile-exp use op indent exps)
- (define (par x indent)
- (if (or (pair? x) (symbol? x))
- (begin
- (out CONTLINE #\()
- (compile-exp NONE use (+ 1 indent) x)
- (out CONTLINE #\)))
- (compile-exp NONE use indent x)))
- (cond ((eqv? #\, op)
- (out CONTLINE #\()
- (if (not (null? exps))
- (begin (compile-exp NONE use indent (car exps))
- (set! exps (cdr exps))))
- (for-each
- (lambda (x)
- (out CONTLINE op #\ )
- (compile-exp NONE use indent x))
- exps)
- (out CONTLINE #\)))
- (else
- (if (not (null? exps))
- (begin (par (car exps) indent)
- (set! exps (cdr exps))))
- (for-each
- (lambda (x)
- (out (if (and (string? op) (char=? #\ (string-ref op 0)))
- indent CONTLINE)
- op)
- (par x (+ (if (char? op) 1 (string-length op)) indent)))
- exps))))
-